home *** CD-ROM | disk | FTP | other *** search
- #include <Events.h>
- #include <OSEvents.h>
- #include <OSUtils.h>
- #include <Dialogs.h>
- #include <Packages.h>
- #include <Retrace.h>
- #include <Traps.h>
-
- #define INTERVAL 6
- #define rInfoDialog 140
- #define rStatTextItem 2
-
- /*
- * These are globals which will be referenced from our VBL Task
- */
- long gCounter; /* Counter incremented each time our VBL gets called */
-
- /*
- * Define a struct to keep track of what we need. Put theVBLTask into the
- * struct first because its address will be passed to our VBL task in A0
- */
- struct VBLRec {
- VBLTask theVBLTask; /* the VBL task itself */
- long VBLA5; /* saved CurrentA5 where we can find it */
- };
- typedef struct VBLRec VBLRec, *VBLRecPtr;
-
- /*
- * GetVBLRec returns the address of the VBLRec associated with our VBL task.
- * This works because on entry into the VBL task, A0 points to the theVBLTask
- * field in the VBLRec record, which is the first field in the record and
- * is the address we return. Note that this method works whether the VBLRec
- * is allocated globally, in the heap (as long as the record is locked in
- * memory) or if it is allocated on the stack as is the case in this example.
- * In the latter case this is OK as long as the procedure which installed the
- * task does not exit while the task is running. This trick allows us to get
- * to the saved A5, but it could also be used to get to anything we wanted to
- * store in the record.
- */
- VBLRecPtr GetVBLRec ()
- = 0x2008; /* MOVE.L A0,D0 */
-
- /*
- * DoVBL is called only by StartVBL ()
- */
- void DoVBL (VRP)
- VBLRecPtr VRP;
- {
- gCounter++; /* Show we can set a global */
- VRP->theVBLTask.vblCount = INTERVAL; /* Set ourselves to run again */
- }
-
- /*
- * This is the actual VBL task code. It uses GetVBLRec to get our VBL record
- * and properly set up A5. Having done that, it calls DoVBL to increment a
- * global counter and sets itself to run again. Because of the vagaries of
- * MPW C 3.0 optimization, it calls a separate routine to actually access
- * global variables. See Tech Note #208 - "Setting and Restoring A5" for the
- * reasons for this, as well as for a description of SetA5.
- */
- void StartVBL ()
- {
- long curA5;
- VBLRecPtr recPtr;
-
- recPtr = GetVBLRec (); /* First get our record */
- curA5 = SetA5 (recPtr->VBLA5);/* Get the saved A5 */
-
- /* Now we can access globals */
- DoVBL (recPtr); /* Call another routine to do actual work */
-
- (void) SetA5 (curA5); /* Restore old A5 */
- }
-
- /*
- * InstallVBL creates a dialog just to demonstrate that the global variable
- * is being updated by the VBL Task. Before installing the VBL, we store
- * our A5 in the actual VBL Task record, using SetCurrentA5 described in
- * Tech Note #208. We'll run the VBL, showing the counter being incremented,
- * until the mouse button is clicked. Then we remove the VBL Task, close the
- * dialog, and remove the mouse down events to prevent the application from
- * being inadvertently switched by MultiFinder.
- */
- void InstallCVBL ()
- {
- VBLRec theVBLRec;
- DialogPtr infoDPtr;
- DialogRecord infoDStorage;
- Str255 numStr;
- OSErr theErr;
- Handle theItemHandle;
- short theItemType;
- long lCounter;
- Rect theRect;
-
- gCounter = 0; /* Initialize our global counter */
- infoDPtr = GetNewDialog (rInfoDialog, (Ptr) &infoDStorage, (WindowPtr) -1);
- DrawDialog (infoDPtr);
- GetDItem (infoDPtr, rStatTextItem, &theItemType, &theItemHandle,
- &theRect);
-
- /*
- * Store the current value of A5 in the MyA5 field. For more
- * information on SetCurrentA5, see Tech Note #208 - "Setting and
- * Restoring A5".
- */
- theVBLRec.VBLA5 = SetCurrentA5 ();
- /* Set the address of our routine */
- theVBLRec.theVBLTask.vblAddr = (VBLProcPtr) StartVBL;
- theVBLRec.theVBLTask.vblCount = INTERVAL; /* Frequency of task, in ticks */
- theVBLRec.theVBLTask.qType = vType; /* qElement is a VBL task */
- theVBLRec.theVBLTask.vblPhase = 0;
-
- /* Now install the VBL task */
- theErr = VInstall ((QElemPtr)&theVBLRec.theVBLTask);
-
- if (!theErr) {
- lCounter = -1; /* Force the initial update */
- do {
- if (lCounter != gCounter) {
- NumToString (gCounter, numStr);
- SetIText (theItemHandle, numStr);
- lCounter = gCounter;
- }
- } while (!Button ());
- theErr = VRemove ((QElemPtr)&theVBLRec.theVBLTask); /* Remove it when done */
- }
-
- /* Finish up */
- CloseDialog (infoDPtr); /* Get rid of our dialog */
- FlushEvents (mDownMask, 0); /* Flush all mouse down events */
- }
-